﻿*&---------------------------------------------------------------------*
*& Report  ZBLACKJACK
*& Самый настоящий блэкджек
*&---------------------------------------------------------------------*
*& Иван / 2013 / v1.00
*& http://code.google.com/p/abap-entropii-net/
*& Licensed under the Apache License, Version 2.0
*&---------------------------------------------------------------------*
report  zblackjack.

types: begin of t_card,
        suit(1) type c,
        face(1) type c,
      end of t_card.

types: t_deck type table of t_card.

data: gt_deck type t_card occurs 0 with header line.
data: gt_hand_d type t_card occurs 0 with header line.
data: gt_hand_u type t_card occurs 0 with header line.

data: gt_suits type t_card-suit occurs 0 with header line.
data: gt_faces type t_card-face occurs 0 with header line.

data: gv_finish(1) type c.
data: gv_unicode(1) type c.

data: begin of hand_u,
        c01(2) type c, "Карта №1
        c02(2) type c,
        c03(2) type c,
        c04(2) type c,
        c05(2) type c,
        c06(2) type c,
        c07(2) type c,
        c08(2) type c,
        c09(2) type c,
        c10(2) type c,
        cxx    type i, "Очки
        cmx    type i, "Баланс
        bet    type i, "Ставка
      end of hand_u.
data: hand_d like hand_u.

initialization.

  call function '/BDL/CHECK_UNICODE'
    importing
      ef_is_unicode = gv_unicode.
  if gv_unicode = 'X'.
    append '♠' to gt_suits.
    append '♣' to gt_suits.
    append '♥' to gt_suits.
    append '♦' to gt_suits.
  elseif sy-langu = 'R'.
    append 'П' to gt_suits.
    append 'К' to gt_suits.
    append 'Ч' to gt_suits.
    append 'Б' to gt_suits.
  else.
    append 'S' to gt_suits.
    append 'C' to gt_suits.
    append 'H' to gt_suits.
    append 'D' to gt_suits.
  endif.

  append 'A' to gt_faces.
  append '2' to gt_faces.
  append '3' to gt_faces.
  append '4' to gt_faces.
  append '5' to gt_faces.
  append '6' to gt_faces.
  append '7' to gt_faces.
  append '8' to gt_faces.
  append '9' to gt_faces.
  append 'X' to gt_faces.
  append 'J' to gt_faces.
  append 'Q' to gt_faces.
  append 'K' to gt_faces.

  import hand_u-cmx from memory id 'ZBJ'.
  if sy-subrc = 0.
    hand_d-cmx = 10000 - hand_u-cmx.
  else.
    hand_u-cmx = 500.
    hand_d-cmx = 9500.
  endif.

*&---------------------------------------------------------------------*
*&      Form  reset
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form reset.
  refresh gt_deck.
  refresh gt_hand_u.
  refresh gt_hand_d.

  loop at gt_suits.
    loop at gt_faces.
      gt_deck-suit = gt_suits.
      gt_deck-face = gt_faces.
      append gt_deck.
    endloop.
  endloop.

  gv_finish = ' '.
  hand_u-bet = 10.
endform.                    "reset


*&---------------------------------------------------------------------*
*&      Form  shuffle
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form shuffle.
  data: lv_seed type i.
  lv_seed = sy-uzeit.
  data: cl_prng type ref to cl_abap_random_int.
  call method cl_abap_random_int=>create
    exporting
      seed = lv_seed
      min  = 1
      max  = 52
    receiving
      prng = cl_prng.
  do 2704 times. "Swap random cards: A <-> B

    data: lv_tabix_a type i.
    data: lv_tabix_b type i.

    lv_tabix_a = cl_prng->get_next( ).
    lv_tabix_b = cl_prng->get_next( ).

    data: ls_card_a type t_card.
    data: ls_card_b type t_card.

    read table gt_deck index  lv_tabix_a into ls_card_a.
    read table gt_deck index  lv_tabix_b into ls_card_b.

    modify gt_deck  index lv_tabix_a from ls_card_b.
    modify gt_deck  index lv_tabix_b from ls_card_a.
  enddo.

  do 208 times. " Random A - go to last, Random B - go to first
    lv_tabix_a = cl_prng->get_next( ).
    lv_tabix_b = cl_prng->get_next( ).

    read table gt_deck index  lv_tabix_a into ls_card_a.
    delete  gt_deck   index  lv_tabix_a.
    append ls_card_a to gt_deck.

    read table gt_deck index  lv_tabix_b into ls_card_b.
    delete  gt_deck   index  lv_tabix_b.
    gt_hand_d[] = gt_deck[].
    refresh gt_deck.
    append ls_card_b to gt_deck.
    loop at gt_hand_d. append gt_hand_d to gt_deck. endloop.
    refresh gt_hand_d.
  enddo.

endform.                    "shuffle

start-of-selection.
  perform new_game.
  if sy-langu = 'R'.
    call screen 2000.
  else.
    call screen 2001.
  endif.

end-of-selection.

*&---------------------------------------------------------------------*
*&      Module  STATUS_2000  OUTPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
module status_2000 output.
  set pf-status 'STD'.
  set titlebar 'USER'.

  data: hand_u_c00 like hand_u-c01.
  do 10 times varying hand_u_c00 from hand_u-c01 next hand_u-c02.
    clear gt_hand_u. read table gt_hand_u index sy-index. hand_u_c00 = gt_hand_u.
  enddo.
  data: hand_d_c00 like hand_d-c01.
  do 10 times varying hand_d_c00 from hand_d-c01 next hand_d-c02.
    clear gt_hand_d. read table gt_hand_d index sy-index. hand_d_c00 = gt_hand_d.
  enddo.

  perform check_hand using gt_hand_u[] changing hand_u-cxx.
  perform check_hand using gt_hand_d[] changing hand_d-cxx.

  loop at screen.
    if screen-name = 'BTN_NEW'.
      if gv_finish = ' '.
        screen-invisible = '1'.
      else.
        screen-invisible = '0'.
      endif.

    elseif screen-name = 'BTN_ADD' or screen-name = 'BTN_STOP' or screen-name = 'BTN_X2'.
      if gv_finish = 'X'.
        screen-invisible = '1'.
      else.
        screen-invisible = '0'.
      endif.
    endif.

    modify screen.
  endloop.

endmodule.                 " STATUS_2000  OUTPUT

*&---------------------------------------------------------------------*
*&      Form  check_hand
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->IT_HAND    text
*      -->SCORE      text
*----------------------------------------------------------------------*
form check_hand using it_hand type t_deck changing score.
  data: ls_deck type line of t_deck.
  score = 0.
  loop at it_hand into ls_deck.
    case ls_deck-face.
      when 'A'.
        if score < 11.
          add 11 to score.
        elseif score = 11 and sy-tabix = 2.
          add 10 to score. "A+A=Blackjack
        else.
          add 1 to score.
        endif.
      when '2'. add 2 to score.
      when '3'. add 3 to score.
      when '4'. add 4 to score.
      when '5'. add 5 to score.
      when '6'. add 6 to score.
      when '7'. add 7 to score.
      when '8'. add 8 to score.
      when '9'. add 9 to score.
      when 'X'. add 10 to score.
      when 'J'. add 10 to score.
      when 'Q'. add 10 to score.
      when 'K'. add 10 to score.
    endcase.
  endloop.

endform.                    "check_hand


*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_2000  INPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
module user_command_2000 input.
  case sy-ucomm.
    when 'BACK'. leave to screen 0.
    when 'EXIT'. leave program.
    when 'ADD'.
      check gv_finish = ' '.
      perform make_move_u.
    when 'STOP'.
      check gv_finish = ' '.
      perform process_dealer.
      perform calc_result.
    when 'X2'.
      check gv_finish = ' '.
      hand_u-bet = hand_u-bet * 2.
      perform make_move_u.

    when 'NEW'.
      check gv_finish = 'X'.
      if hand_u-cmx < 0.
        message 'Для пополнения баланса отправьте текст с суммой на номер +7(701)288-32-08'(777) type 'E'.
      endif.
      perform new_game.

  endcase.

endmodule.                 " USER_COMMAND_2000  INPUT

*&---------------------------------------------------------------------*
*&      Form  new_game
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form new_game.
  gv_finish = ' '.
  perform reset.
  perform shuffle.
  perform make_move_u.
  perform make_move_d.
endform.                    "new_game

*&---------------------------------------------------------------------*
*&      Form  calc_result
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form calc_result.
  if hand_u-cxx = 21.
    message 'Блэкджек!'(100) type 'S'.
    hand_u-cmx = hand_u-cmx + hand_u-bet * '1.5'.
    hand_d-cmx = hand_d-cmx - hand_u-bet * '1.5'.
  elseif hand_u-cxx > 21.
    message 'Перебор у игрока'(101) type 'S'.
    hand_u-cmx = hand_u-cmx - hand_u-bet.
    hand_d-cmx = hand_d-cmx + hand_u-bet.
  elseif hand_d-cxx > 21.
    message 'Перебор у дилера'(102) type 'S'.
    hand_u-cmx = hand_u-cmx + hand_u-bet.
    hand_d-cmx = hand_d-cmx - hand_u-bet.
  elseif hand_u-cxx = hand_d-cxx.
    message 'Ничья - победа казино'(103) type 'S'.
    hand_u-cmx = hand_u-cmx + hand_u-bet.
    hand_d-cmx = hand_d-cmx - hand_u-bet.
  elseif hand_u-cxx >= hand_d-cxx.
    message 'Победа игрока'(104) type 'S'.
    hand_u-cmx = hand_u-cmx + hand_u-bet.
    hand_d-cmx = hand_d-cmx - hand_u-bet.
  else.
    message 'Победа дилера'(105) type 'S'.
    hand_u-cmx = hand_u-cmx - hand_u-bet.
    hand_d-cmx = hand_d-cmx + hand_u-bet.
  endif.

  export hand_u-cmx to memory id 'ZBJ'.

  gv_finish = 'X'.
endform.                    "calc_result

*&---------------------------------------------------------------------*
*&      Form  process_dealer
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form process_dealer.
  do.

    read table gt_deck index 1 into gt_hand_d.
    append gt_hand_d.
    delete gt_deck index 1.

    perform check_hand using gt_hand_d[] changing hand_d-cxx.

    if hand_d-cxx >= hand_u-cxx .
      exit. "Простая логика - останавливаемся если бьём игрока
    endif.

  enddo.
endform.                    "process_dealer

*&---------------------------------------------------------------------*
*&      Form  add_card
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form add_card using hand type t_deck.
  data: ls_card type line of t_deck.

  read table gt_deck index 1 into ls_card.
  append ls_card to hand.
  delete gt_deck index 1.
endform.                    "add_card

*&---------------------------------------------------------------------*
*&      Form  make_move_u
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form make_move_u.
  perform add_card using gt_hand_u[].
  perform check_hand using gt_hand_u[] changing hand_u-cxx.
  if hand_u-cxx >= 21.
    perform calc_result.
  endif.
endform.                    "make_move_u

*&---------------------------------------------------------------------*
*&      Form  make_move_d
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
form make_move_d.
  perform add_card using gt_hand_d[].
  perform check_hand using gt_hand_d[] changing hand_d-cxx.
  if hand_d-cxx >= 21.
    perform calc_result.
  endif.
endform.                    "make_move_u